﻿using System;
using System.Collections.Generic;
using System.Text;
using Pixysoft.Framework.Reflection.Core;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections;

namespace Pixysoft.Framework.Reflection.Controller
{
    /// <summary>
    /// 输入对象元数据 构造结构dummy 不带数据
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    delegate IDummyType DummyTypeHandler();

    /// <summary>
    /// structure serialize
    /// </summary>
    partial class DummyTypeHandlerFactory
    {
        private const BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;

        /// <summary>
        /// 给出object 获取property/attribute/以及对应的数据
        /// </summary>
        /// <param name="objectType"></param>
        /// <returns></returns>
        internal static DummyTypeHandler CreateDummyTypeHandler(Type objectType)
        {
            DynamicMethod dynamicMethod = new DynamicMethod("D" + Guid.NewGuid().ToString().Replace("-", "_"),
                MethodAttributes.Static | MethodAttributes.Public,
                CallingConventions.Standard,
                typeof(IDummyType),
                new Type[] { typeof(Type) },
                typeof(DummyTypeHandlerFactory),
                true);

            DotNetPropertyType propertyType = Pixysoft.Tools.ParserHelper.GetPropertyType(objectType);

            ILGenerator generator = dynamicMethod.GetILGenerator();

            switch (propertyType)
            {
                case DotNetPropertyType.InterfaceList:
                case DotNetPropertyType.BinaryList:
                case DotNetPropertyType.EnumList:
                case DotNetPropertyType.ObjectList:
                case DotNetPropertyType.ValueList:
                    {
                        Type arrayObjectType = objectType.GetGenericArguments()[0];

                        CreateListStructureIl(generator, propertyType, objectType, arrayObjectType);

                        return (DummyTypeHandler)dynamicMethod.CreateDelegate(typeof(DummyTypeHandler));
                    }

                case DotNetPropertyType.InterfaceArray://也有可能遇到接口 因为这里仅仅对元数据进行返回，不是对实际数据反射
                case DotNetPropertyType.EnumArray:
                case DotNetPropertyType.ValueArray:
                case DotNetPropertyType.ObjectArray:
                    {
                        Type arrayObjectType = objectType.GetElementType();

                        CreateCollectionStructureIl(generator, propertyType, objectType, arrayObjectType);

                        return (DummyTypeHandler)dynamicMethod.CreateDelegate(typeof(DummyTypeHandler));
                    }

                case DotNetPropertyType.Binary:
                    {
                        CreateBinaryStructureIl(generator, objectType);

                        return (DummyTypeHandler)dynamicMethod.CreateDelegate(typeof(DummyTypeHandler));
                    }


                case DotNetPropertyType.Interface:
                case DotNetPropertyType.Object:
                    {
                        break;
                    }

                case DotNetPropertyType.Enum:
                    {
                        CreateEnumStructureIl(generator, objectType);

                        return (DummyTypeHandler)dynamicMethod.CreateDelegate(typeof(DummyTypeHandler));
                    }
                case DotNetPropertyType.Value:
                    {
                        CreateValueStructureIl(generator, Pixysoft.Tools.ParserHelper.GetDataTypeByType(objectType), objectType);

                        return (DummyTypeHandler)dynamicMethod.CreateDelegate(typeof(DummyTypeHandler));
                    }

                case DotNetPropertyType.Unknown:
                default:
                    throw new Exception("unknown object type.");
            }



            CreateDummyTypeIl(generator, propertyType, objectType);

            BufferDummyTypeStructureIl(generator);

            if (objectType.Equals(typeof(object)) || objectType.Equals(typeof(Type)))//不支持object类型
            {
                OpCodesFactory.LdLocalVariable(generator, 0);
                OpCodesFactory.ReturnMethod(generator);
                return (DummyTypeHandler)dynamicMethod.CreateDelegate(typeof(DummyTypeHandler));
            }

            if (objectType.GetCustomAttributes(typeof(DummySerializeIgnoreAttribute), false).Length > 0)
            {
                OpCodesFactory.LdLocalVariable(generator, 0);
                OpCodesFactory.ReturnMethod(generator);
                return (DummyTypeHandler)dynamicMethod.CreateDelegate(typeof(DummyTypeHandler));
            }

            CreatePropertyStructureIl(generator, objectType);

            CreateMethodStructureIl(generator, objectType);

            if (!ReflectionFactory.IsInheritFrom(objectType, typeof(Attribute)))
            {
                CreateAttributeIl(generator, objectType);

                CreateInterfacesIl(generator, objectType);
            }

            OpCodesFactory.LdLocalVariable(generator, 0);
            OpCodesFactory.ReturnMethod(generator);
            return (DummyTypeHandler)dynamicMethod.CreateDelegate(typeof(DummyTypeHandler));
        }

        private static void BufferDummyTypeStructureIl(ILGenerator generator)
        {
            //L_0017: ldloc.0 
            //L_0018: call void Pixysoft.Framework.Reflection.Controller.DummyTypeSerializeHandlerFactory::BufferDummyStructureObject(class Pixysoft.Framework.Reflection.IDummyType)
            //L_001d: nop 

            OpCodesFactory.LdLocalVariable(generator, 0);
            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, DummyTypeHandlerFactory.BufferDummyTypeObjectAttribute>(generator);
            OpCodesFactory.Donothing(generator);

        }

        private static void CreatePropertyStructureIl(ILGenerator generator, Type objectType)
        {
            //创建property 
            //因为根据了实际的objectType获取property，所以集成的property也能获得
            foreach (PropertyInfo info in objectType.GetProperties())
            {
                if (Pixysoft.Reflection.ReflectHelper.Instance.IsIndexProperty(info))
                    continue;

                if (info.DeclaringType.GetCustomAttributes(typeof(DummySerializeIgnoreAttribute), false).Length > 0)
                    continue;

                //判断属性是否可读 这里比反射要求严格 因为仅仅根据元数据 不是实际数据

                if (!info.CanRead)
                    continue;


                //因为动态代理没有property 所以不用考虑

                if (info.PropertyType.Equals(typeof(object)))//针对attribute  过滤掉object属性
                    continue;

                DotNetPropertyType objectPropertyType = Pixysoft.Tools.ParserHelper.GetPropertyType(info.PropertyType);

                DotNetDataType objectDataType = Pixysoft.Tools.ParserHelper.GetDataTypeByType(info.PropertyType);

                string propertyName = info.Name;


                //先创建property的声明
                //string name, bool canread, bool canwrite
                OpCodesFactory.LdLocalVariable(generator, 0);
                OpCodesFactory.LdString(generator, propertyName);
                OpCodesFactory.LdBoolean(generator, info.CanRead);
                OpCodesFactory.LdBoolean(generator, info.CanWrite);
                OpCodesFactory.CallVirtMethod<DummyType, DummyType.CreatePropertyAttribute>(generator);



                //开始设置property的值 是个空value的dumptype

                switch (objectPropertyType)
                {
                    case DotNetPropertyType.Enum:
                        {
                            //string nameSpace, string fullname, string name, object value

                            OpCodesFactory.LdString(generator, Pixysoft.Tools.AssemblyHelper.Instance.GetAssemblyName(info.PropertyType.Assembly));
                            OpCodesFactory.LdString(generator, Pixysoft.Tools.AssemblyHelper.Instance.GetAssemblyFileName(info.PropertyType.Assembly));
                            OpCodesFactory.LdString(generator, info.PropertyType.Namespace);
                            OpCodesFactory.LdString(generator, info.PropertyType.FullName);
                            OpCodesFactory.LdString(generator, info.PropertyType.Name);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeEnumAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyPropertyInfo, DummyPropertyInfo.PropertyTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }
                    case DotNetPropertyType.Value:
                        {
                            //string fullname, string name, DotNetDataType datatype,

                            OpCodesFactory.LdString(generator, info.PropertyType.FullName);
                            OpCodesFactory.LdString(generator, info.PropertyType.Name);
                            OpCodesFactory.LdIntOrEnum(generator, (int)objectDataType);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeValueAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyPropertyInfo, DummyPropertyInfo.PropertyTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }
                    case DotNetPropertyType.Object:
                    case DotNetPropertyType.Interface:
                        {
                            //string nameSpace, string fullname, string name, Type value

                            OpCodesFactory.LdString(generator, info.PropertyType.Namespace);
                            OpCodesFactory.LdString(generator, info.PropertyType.FullName);
                            OpCodesFactory.LdString(generator, info.PropertyType.Name);
                            OpCodesFactory.LdType(generator, info.PropertyType);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeObjectAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyPropertyInfo, DummyPropertyInfo.PropertyTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }
                    case DotNetPropertyType.Binary:
                        {
                            //string fullname, string name, object value

                            OpCodesFactory.LdString(generator, info.PropertyType.FullName);
                            OpCodesFactory.LdString(generator, info.PropertyType.Name);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeBinaryAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyPropertyInfo, DummyPropertyInfo.PropertyTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }

                    case DotNetPropertyType.EnumArray:
                    case DotNetPropertyType.ValueArray:
                    case DotNetPropertyType.ObjectArray:
                    case DotNetPropertyType.InterfaceArray:
                        {
                            //DotNetPropertyType propertyType, string nameSpace, string fullname, string name, Type elementType

                            OpCodesFactory.LdIntOrEnum(generator, (int)objectPropertyType);
                            OpCodesFactory.LdString(generator, info.PropertyType.Namespace);
                            OpCodesFactory.LdString(generator, info.PropertyType.FullName);
                            OpCodesFactory.LdString(generator, info.PropertyType.Name);
                            //范型的metadatatoken和element没有关系 导致出错
                            OpCodesFactory.LdType(generator, info.PropertyType.GetElementType());
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeCollectionAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyPropertyInfo, DummyPropertyInfo.PropertyTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }
                    case DotNetPropertyType.EnumList:
                    case DotNetPropertyType.ValueList:
                    case DotNetPropertyType.ObjectList:
                    case DotNetPropertyType.InterfaceList:
                    case DotNetPropertyType.BinaryList:
                        {
                            //DotNetPropertyType propertyType, string nameSpace, string fullname, string name, Type elementType

                            OpCodesFactory.LdIntOrEnum(generator, (int)objectPropertyType);
                            OpCodesFactory.LdString(generator, info.PropertyType.Namespace);
                            OpCodesFactory.LdString(generator, StringHelper.GetListFullName(info.PropertyType));
                            OpCodesFactory.LdString(generator, info.PropertyType.Name);
                            OpCodesFactory.LdType(generator, info.PropertyType.GetGenericArguments()[0]);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeListAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyPropertyInfo, DummyPropertyInfo.PropertyTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }

                    case DotNetPropertyType.Unknown:
                    default:
                        {
                            break;
                        }
                }

                //初始化attribute
                CreatePropertyAttributeIl(generator, info);
            }
        }

        private static void CreateMethodStructureIl(ILGenerator generator, Type objectType)
        {
            //创建method

            foreach (MethodInfo info in objectType.GetMethods(flags))
            {
                if (info.DeclaringType.Equals(typeof(object)))//过滤object的方法
                    continue;

                if (info.DeclaringType.Equals(typeof(DynamicTransparentProxyBase)))//过滤掉关于动态代理的方法
                    continue;

                if (info.DeclaringType.GetCustomAttributes(typeof(DummySerializeIgnoreAttribute), false).Length > 0)//有可能存在继承关系导致越类
                    continue;

                if (info.DeclaringType.Equals(typeof(MarshalByRefObject)))
                    continue;

                if (info.DeclaringType.Equals(typeof(ContextBoundObject)))
                    continue;

                DotNetPropertyType objectReturnType = Pixysoft.Tools.ParserHelper.GetPropertyType(info.ReturnType);

                DotNetDataType objectDataType = Pixysoft.Tools.ParserHelper.GetDataTypeByType(info.ReturnType);

                string methodName = info.Name;


                //先创建method的声明
                //string name, bool canread, bool canwrite
                OpCodesFactory.LdLocalVariable(generator, 0);
                OpCodesFactory.LdString(generator, methodName);
                OpCodesFactory.CallVirtMethod<DummyType, DummyType.CreateMethodAttribute>(generator);


                //开始设置property的值 是个空value的dumptype

                switch (objectReturnType)
                {
                    case DotNetPropertyType.Enum:
                        {
                            //string nameSpace, string fullname, string name, object value

                            OpCodesFactory.LdString(generator, Pixysoft.Tools.AssemblyHelper.Instance.GetAssemblyName(info.ReturnType.Assembly));
                            OpCodesFactory.LdString(generator, Pixysoft.Tools.AssemblyHelper.Instance.GetAssemblyFileName(info.ReturnType.Assembly));
                            OpCodesFactory.LdString(generator, info.ReturnType.Namespace);
                            OpCodesFactory.LdString(generator, info.ReturnType.FullName);
                            OpCodesFactory.LdString(generator, info.ReturnType.Name);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeEnumAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyMethodInfo, DummyMethodInfo.ReturnTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }
                    case DotNetPropertyType.Value:
                        {
                            //string fullname, string name, DotNetDataType datatype, object value

                            OpCodesFactory.LdString(generator, info.ReturnType.FullName);
                            OpCodesFactory.LdString(generator, info.ReturnType.Name);
                            OpCodesFactory.LdIntOrEnum(generator, (int)objectDataType);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeValueAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyMethodInfo, DummyMethodInfo.ReturnTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }
                    case DotNetPropertyType.Object:
                    case DotNetPropertyType.Interface:
                        {
                            //string nameSpace, string fullname, string name, Type value

                            OpCodesFactory.LdString(generator, info.ReturnType.Namespace);
                            OpCodesFactory.LdString(generator, info.ReturnType.FullName);
                            OpCodesFactory.LdString(generator, info.ReturnType.Name);
                            OpCodesFactory.LdType(generator, info.ReturnType);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeObjectAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyMethodInfo, DummyMethodInfo.ReturnTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }
                    case DotNetPropertyType.Binary:
                        {
                            //string fullname, string name, object value

                            OpCodesFactory.LdString(generator, info.ReturnType.FullName);
                            OpCodesFactory.LdString(generator, info.ReturnType.Name);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeBinaryAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyMethodInfo, DummyMethodInfo.ReturnTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }

                    case DotNetPropertyType.EnumArray:
                    case DotNetPropertyType.ValueArray:
                    case DotNetPropertyType.ObjectArray:
                    case DotNetPropertyType.InterfaceArray:
                        {
                            //DotNetPropertyType propertyType, string nameSpace, string fullname, string name, Type elementType

                            OpCodesFactory.LdIntOrEnum(generator, (int)objectReturnType);
                            OpCodesFactory.LdString(generator, info.ReturnType.Namespace);
                            OpCodesFactory.LdString(generator, info.ReturnType.FullName);
                            OpCodesFactory.LdString(generator, info.ReturnType.Name);
                            OpCodesFactory.LdType(generator, info.ReturnType.GetElementType());
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeCollectionAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyMethodInfo, DummyMethodInfo.ReturnTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }
                    case DotNetPropertyType.EnumList:
                    case DotNetPropertyType.ValueList:
                    case DotNetPropertyType.ObjectList:
                    case DotNetPropertyType.InterfaceList:
                    case DotNetPropertyType.BinaryList:
                        {
                            //DotNetPropertyType propertyType, string nameSpace, string fullname, string name, Type elementType

                            OpCodesFactory.LdIntOrEnum(generator, (int)objectReturnType);
                            OpCodesFactory.LdString(generator, info.ReturnType.Namespace);
                            OpCodesFactory.LdString(generator, StringHelper.GetListFullName(info.ReturnType));
                            OpCodesFactory.LdString(generator, info.ReturnType.Name);
                            OpCodesFactory.LdType(generator, info.ReturnType.GetGenericArguments()[0]);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeListAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyMethodInfo, DummyMethodInfo.ReturnTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }

                    case DotNetPropertyType.Unknown:
                    default:
                        {
                            break;
                        }
                }


                CreateMethodModifierIl(generator, info);

                //初始化attribute
                CreateMethodAttributeIl(generator, info);

                //初始化参数表
                CreateParameterStructureIl(generator, info);
            }
        }

        private static void CreateMethodModifierIl(ILGenerator generator, MethodInfo info)
        {
            OpCodesFactory.LdLocalVariable(generator, 0);
            OpCodesFactory.CallVirtMethod<DummyType, DummyType.LastMethodAttribute>(generator);
            OpCodesFactory.LdBoolean(generator, info.IsPrivate);
            OpCodesFactory.CallSetvirtProperty<DummyMethodInfo, DummyMethodInfo.IsPrivateAttribute>(generator);

            OpCodesFactory.LdLocalVariable(generator, 0);
            OpCodesFactory.CallVirtMethod<DummyType, DummyType.LastMethodAttribute>(generator);
            OpCodesFactory.LdBoolean(generator, info.IsPublic);
            OpCodesFactory.CallSetvirtProperty<DummyMethodInfo, DummyMethodInfo.IsPublicAttribute>(generator);

            OpCodesFactory.LdLocalVariable(generator, 0);
            OpCodesFactory.CallVirtMethod<DummyType, DummyType.LastMethodAttribute>(generator);
            OpCodesFactory.LdBoolean(generator, info.IsStatic);
            OpCodesFactory.CallSetvirtProperty<DummyMethodInfo, DummyMethodInfo.IsStaticAttribute>(generator);

            OpCodesFactory.LdLocalVariable(generator, 0);
            OpCodesFactory.CallVirtMethod<DummyType, DummyType.LastMethodAttribute>(generator);
            OpCodesFactory.LdBoolean(generator, info.IsVirtual);
            OpCodesFactory.CallSetvirtProperty<DummyMethodInfo, DummyMethodInfo.IsVirtualAttribute>(generator);

        }

        private static void CreateParameterStructureIl(ILGenerator generator, MethodInfo methodInfo)
        {
            //加载最后一个method创建parameter

            foreach (ParameterInfo info in methodInfo.GetParameters())
            {
                DotNetPropertyType objectParameterType = Pixysoft.Tools.ParserHelper.GetPropertyType(info.ParameterType);

                DotNetDataType objectDataType = Pixysoft.Tools.ParserHelper.GetDataTypeByType(info.ParameterType);

                string parameterName = info.Name;

                OpCodesFactory.LdLocalVariable(generator, 0);
                OpCodesFactory.CallVirtMethod<DummyType, DummyType.LastMethodAttribute>(generator);
                OpCodesFactory.LdString(generator, parameterName);
                OpCodesFactory.LdIntOrEnum(generator, info.Position);
                OpCodesFactory.CallVirtMethod<DummyMethodInfo, DummyMethodInfo.CreateParameterAttribute>(generator);

                //开始设置property的值 是个空value的dumptype

                switch (objectParameterType)
                {
                    case DotNetPropertyType.Enum:
                        {
                            //string nameSpace, string fullname, string name, object value

                            OpCodesFactory.LdString(generator, Pixysoft.Tools.AssemblyHelper.Instance.GetAssemblyName(info.ParameterType.Assembly));
                            OpCodesFactory.LdString(generator, Pixysoft.Tools.AssemblyHelper.Instance.GetAssemblyFileName(info.ParameterType.Assembly));
                            OpCodesFactory.LdString(generator, info.ParameterType.Namespace);
                            OpCodesFactory.LdString(generator, info.ParameterType.FullName);
                            OpCodesFactory.LdString(generator, info.ParameterType.Name);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeEnumAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyParameterInfo, DummyParameterInfo.ParameterTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }
                    case DotNetPropertyType.Value:
                        {
                            //string fullname, string name, DotNetDataType datatype

                            OpCodesFactory.LdString(generator, info.ParameterType.FullName);
                            OpCodesFactory.LdString(generator, info.ParameterType.Name);
                            OpCodesFactory.LdIntOrEnum(generator, (int)objectDataType);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeValueAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyParameterInfo, DummyParameterInfo.ParameterTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }
                    case DotNetPropertyType.Object:
                    case DotNetPropertyType.Interface:
                        {
                            //string nameSpace, string fullname, string name, Type value

                            OpCodesFactory.LdString(generator, info.ParameterType.Namespace);
                            OpCodesFactory.LdString(generator, info.ParameterType.FullName);
                            OpCodesFactory.LdString(generator, info.ParameterType.Name);
                            OpCodesFactory.LdType(generator, info.ParameterType);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeObjectAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyParameterInfo, DummyParameterInfo.ParameterTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }
                    case DotNetPropertyType.Binary:
                        {
                            //string fullname, string name, object value

                            OpCodesFactory.LdString(generator, info.ParameterType.FullName);
                            OpCodesFactory.LdString(generator, info.ParameterType.Name);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeBinaryAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyParameterInfo, DummyParameterInfo.ParameterTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }

                    case DotNetPropertyType.EnumArray:
                    case DotNetPropertyType.ValueArray:
                    case DotNetPropertyType.ObjectArray:
                    case DotNetPropertyType.InterfaceArray:
                        {
                            //DotNetPropertyType propertyType, string nameSpace, string fullname, string name, Type elementType

                            OpCodesFactory.LdIntOrEnum(generator, (int)objectParameterType);
                            OpCodesFactory.LdString(generator, info.ParameterType.Namespace);
                            OpCodesFactory.LdString(generator, info.ParameterType.FullName);
                            OpCodesFactory.LdString(generator, info.ParameterType.Name);
                            OpCodesFactory.LdType(generator, info.ParameterType.GetElementType());
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeCollectionAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyParameterInfo, DummyParameterInfo.ParameterTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }
                    case DotNetPropertyType.EnumList:
                    case DotNetPropertyType.ValueList:
                    case DotNetPropertyType.ObjectList:
                    case DotNetPropertyType.InterfaceList:
                    case DotNetPropertyType.BinaryList:
                        {
                            //DotNetPropertyType propertyType, string nameSpace, string fullname, string name, Type elementType

                            OpCodesFactory.LdIntOrEnum(generator, (int)objectParameterType);
                            OpCodesFactory.LdString(generator, info.ParameterType.Namespace);
                            OpCodesFactory.LdString(generator, StringHelper.GetListFullName(info.ParameterType));
                            OpCodesFactory.LdString(generator, info.ParameterType.Name);
                            OpCodesFactory.LdType(generator, info.ParameterType.GetGenericArguments()[0]);
                            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeListAttribute>(generator);
                            OpCodesFactory.CallSetvirtProperty<DummyParameterInfo, DummyParameterInfo.ParameterTypeAttribute>(generator);
                            OpCodesFactory.Donothing(generator);

                            break;
                        }

                    case DotNetPropertyType.Unknown:
                    default:
                        {
                            break;
                        }
                }
            }
        }

        private static void CreateListStructureIl(ILGenerator generator, DotNetPropertyType propertyType, Type objectType, Type objectElementType)
        {
            //DotNetPropertyType propertyType, string nameSpace, string fullname, string name, Type elementType

            OpCodesFactory.LdIntOrEnum(generator, (int)propertyType);
            OpCodesFactory.LdString(generator, objectType.Namespace);
            OpCodesFactory.LdString(generator, StringHelper.GetListFullName(objectType));
            OpCodesFactory.LdString(generator, objectType.Name);
            OpCodesFactory.LdType(generator, objectElementType);
            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeListAttribute>(generator);
            OpCodesFactory.ReturnMethod(generator);
        }

        private static void CreateCollectionStructureIl(ILGenerator generator, DotNetPropertyType propertyType, Type objectType, Type objectElementType)
        {
            //DotNetPropertyType propertyType, string nameSpace, string fullname, string name, Type elementType

            OpCodesFactory.LdIntOrEnum(generator, (int)propertyType);
            OpCodesFactory.LdString(generator, objectType.Namespace);
            OpCodesFactory.LdString(generator, objectType.FullName);
            OpCodesFactory.LdString(generator, objectType.Name);
            OpCodesFactory.LdType(generator, objectElementType);
            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeCollectionAttribute>(generator);
            OpCodesFactory.ReturnMethod(generator);
        }

        private static void CreateBinaryStructureIl(ILGenerator generator, Type objectType)
        {
            //string fullname, string name, object value

            //L_0001: ldstr ""
            //   L_0006: ldstr ""
            //   L_000b: ldarg.1 
            //   L_000c: call

            OpCodesFactory.LdString(generator, objectType.FullName);
            OpCodesFactory.LdString(generator, objectType.Name);
            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeBinaryAttribute>(generator);
            OpCodesFactory.ReturnMethod(generator);
        }

        private static void CreateEnumStructureIl(ILGenerator generator, Type objectType)
        {
            OpCodesFactory.LdString(generator, Pixysoft.Tools.AssemblyHelper.Instance.GetAssemblyName(objectType.Assembly));
            OpCodesFactory.LdString(generator, Pixysoft.Tools.AssemblyHelper.Instance.GetAssemblyFileName(objectType.Assembly));
            OpCodesFactory.LdString(generator, objectType.Namespace);
            OpCodesFactory.LdString(generator, objectType.FullName);
            OpCodesFactory.LdString(generator, objectType.Name);
            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeEnumAttribute>(generator);
            OpCodesFactory.ReturnMethod(generator);
        }

        private static void CreateValueStructureIl(ILGenerator generator, DotNetDataType dataType, Type objectType)
        {
            //string fullname, string name, DotNetDataType datatype, object value            

            OpCodesFactory.LdString(generator, objectType.FullName);
            OpCodesFactory.LdString(generator, objectType.Name);
            OpCodesFactory.LdIntOrEnum(generator, (int)dataType);
            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeValueAttribute>(generator);
            OpCodesFactory.ReturnMethod(generator);
        }

        /// <summary>
        /// dummytype/structure
        /// </summary>
        /// <param name="generator"></param>
        /// <param name="info"></param>
        private static void CreateMethodAttributeIl(ILGenerator generator, MemberInfo info)
        {
            //string nameSpace,string fullname, string name, object value

            foreach (CustomAttributeData attributeData in CustomAttributeData.GetCustomAttributes(info))
            {
                Type attributeType = attributeData.Constructor.DeclaringType;

                OpCodesFactory.LdLocalVariable(generator, 0);

                OpCodesFactory.CallVirtMethod<DummyType, DummyType.LastMethodAttribute>(generator);


                //新建attribute实体对象 由于byte被解析为int32 所以无法使用
                int argIndex = 0;
                foreach (ParameterInfo parainfo in attributeData.Constructor.GetParameters())
                {
                    object attributeParameterData = attributeData.ConstructorArguments[argIndex++].Value;

                    if (IlGeneratorSetAttributeValue(generator,
                        Pixysoft.Tools.ParserHelper.GetDataTypeByType(parainfo.ParameterType),
                        attributeParameterData))
                        continue;

                    if (IlGeneratorSetAttributeValue(generator,
                        Pixysoft.Tools.ParserHelper.GetDataType(attributeParameterData),
                        attributeParameterData))
                        continue;

                    if (parainfo.ParameterType.IsEnum)
                    {
                        OpCodesFactory.LdIntOrEnum(generator, (int)attributeParameterData);
                        continue;
                    }

                    //当成string处理

                    if (attributeParameterData == null)
                        OpCodesFactory.LdString(generator, null);
                    else
                        OpCodesFactory.LdString(generator, attributeParameterData.ToString());
                }

                OpCodesFactory.CreateObject(generator, attributeData.Constructor);

                //压入dummy
                OpCodesFactory.CallVirtMethod<DummyMemberInfo, DummyMemberInfo.AddAttributeAttribute>(generator);
                OpCodesFactory.Donothing(generator);
            }
        }

        /// <summary>
        /// dummytype/structure
        /// </summary>
        /// <param name="generator"></param>
        /// <param name="info"></param>
        private static void CreatePropertyAttributeIl(ILGenerator generator, MemberInfo info)
        {
            //string nameSpace,string fullname, string name, object value

            foreach (CustomAttributeData attributeData in CustomAttributeData.GetCustomAttributes(info))
            {
                Type attributeType = attributeData.Constructor.DeclaringType;

                //加载dummytype
                OpCodesFactory.LdLocalVariable(generator, 0);


                //加载lastproperty!!!!!这里就是和dummytype的区别
                OpCodesFactory.CallVirtMethod<DummyType, DummyType.LastPropertyAttribute>(generator);


                //新建attribute实体对象 由于byte被解析为int32 所以无法使用
                int argIndex = 0;
                foreach (ParameterInfo parainfo in attributeData.Constructor.GetParameters())
                {
                    object attributeParameterData = attributeData.ConstructorArguments[argIndex++].Value;

                    if (IlGeneratorSetAttributeValue(generator,
                        Pixysoft.Tools.ParserHelper.GetDataTypeByType(parainfo.ParameterType),
                        attributeParameterData))
                        continue;

                    if (IlGeneratorSetAttributeValue(generator,
                        Pixysoft.Tools.ParserHelper.GetDataType(attributeParameterData),
                        attributeParameterData))
                        continue;

                    if (parainfo.ParameterType.IsEnum)
                    {
                        OpCodesFactory.LdIntOrEnum(generator, (int)attributeParameterData);
                        continue;
                    }

                    //当成string处理

                    if (attributeParameterData == null)
                        OpCodesFactory.LdString(generator, null);
                    else
                        OpCodesFactory.LdString(generator, attributeParameterData.ToString());
                }

                //创建实例对象
                OpCodesFactory.CreateObject(generator, attributeData.Constructor);

                //压入object到attribute
                OpCodesFactory.CallVirtMethod<DummyMemberInfo, DummyMemberInfo.AddAttributeAttribute>(generator);
                OpCodesFactory.Donothing(generator);
            }
        }

        /// <summary>
        /// dummytype/structure
        /// </summary>
        /// <param name="generator"></param>
        /// <param name="info"></param>
        private static void CreateAttributeIl(ILGenerator generator, MemberInfo info)
        {
            //string nameSpace,string fullname, string name, object value

            foreach (CustomAttributeData attributeData in CustomAttributeData.GetCustomAttributes(info))
            {
                Type attributeType = attributeData.Constructor.DeclaringType;

                //加载dummytype
                OpCodesFactory.LdLocalVariable(generator, 0);


                //新建attribute 由于byte被解析为int32 所以无法使用
                int argIndex = 0;
                foreach (ParameterInfo parainfo in attributeData.Constructor.GetParameters())
                {
                    object attributeParameterData = attributeData.ConstructorArguments[argIndex++].Value;

                    if (IlGeneratorSetAttributeValue(generator,
                        Pixysoft.Tools.ParserHelper.GetDataTypeByType(parainfo.ParameterType),
                        attributeParameterData))
                        continue;

                    if (IlGeneratorSetAttributeValue(generator,
                        Pixysoft.Tools.ParserHelper.GetDataType(attributeParameterData),
                        attributeParameterData))
                        continue;

                    if (parainfo.ParameterType.IsEnum)
                    {
                        OpCodesFactory.LdIntOrEnum(generator, (int)attributeParameterData);
                        continue;
                    }

                    //当成string处理

                    if (attributeParameterData == null)
                        OpCodesFactory.LdString(generator, null);
                    else
                        OpCodesFactory.LdString(generator, attributeParameterData.ToString());
                }

                OpCodesFactory.CreateObject(generator, attributeData.Constructor);

                //压入dummy
                OpCodesFactory.CallVirtMethod<DummyMemberInfo, DummyMemberInfo.AddAttributeAttribute>(generator);
                OpCodesFactory.Donothing(generator);
            }
        }

        private static bool IlGeneratorSetAttributeValue(ILGenerator generator, DotNetDataType type, object attributeData)
        {
            switch (type)
            {
                case DotNetDataType.String:
                    {
                        OpCodesFactory.LdString(generator, (string)attributeData);
                        break;
                    }
                case DotNetDataType.Int32:
                    {
                        OpCodesFactory.LdIntOrEnum(generator, (Int32)attributeData);
                        break;
                    }
                case DotNetDataType.Single:
                    {
                        OpCodesFactory.LdFloat(generator, (Single)attributeData);
                        break;
                    }
                case DotNetDataType.Double:
                    {
                        OpCodesFactory.LdDouble(generator, (double)attributeData);
                        break;
                    }
                case DotNetDataType.Int64:
                    {
                        OpCodesFactory.LdLong(generator, (Int64)attributeData);
                        break;
                    }
                case DotNetDataType.Char:
                    {
                        OpCodesFactory.LdChar(generator, (char)attributeData);
                        break;
                    }
                case DotNetDataType.Boolean:
                    {
                        OpCodesFactory.LdBoolean(generator, (bool)attributeData);
                        break;
                    }
                case DotNetDataType.Byte:
                case DotNetDataType.Decimal:
                case DotNetDataType.Object:
                case DotNetDataType.DateTime:
                case DotNetDataType.UNKNOWN:
                default:
                    {
                        return false;
                    }
            }

            return true;
        }


        /// <summary>
        /// typestructure
        /// </summary>
        /// <param name="generator"></param>
        /// <param name="propertyType"></param>
        /// <param name="objectType"></param>
        private static void CreateDummyTypeIl(ILGenerator generator, DotNetPropertyType propertyType, Type objectType)
        {
            //声明局部变量
            generator.DeclareLocal(typeof(DummyType));

            //首先创建dummy
            OpCodesFactory.LdIntOrEnum(generator, (int)propertyType);
            OpCodesFactory.LdString(generator, objectType.Namespace);
            OpCodesFactory.LdString(generator, objectType.FullName);
            OpCodesFactory.LdString(generator, objectType.Name);
            OpCodesFactory.CallMethod<DummyTypeHandlerFactory, PrivateCreateDummyTypeObjectAttribute>(generator);

            //dummy保存在第一个局部变量
            OpCodesFactory.SaveLocalVariable(generator, 0);


            //新建assembly
            OpCodesFactory.LdLocalVariable(generator, 0);
            OpCodesFactory.LdString(generator, objectType.Assembly.GetName().Name);
            OpCodesFactory.LdString(generator, objectType.Assembly.ManifestModule.Name);
            OpCodesFactory.CreateObject<DummyAssembly>(generator, typeof(string), typeof(string));
            OpCodesFactory.CallSetvirtProperty<DummyType, DummyType.AssemblyAttribute>(generator);
            OpCodesFactory.Donothing(generator);
        }

        private static void CreateInterfacesIl(ILGenerator generator, Type objectType)
        {
            foreach (Type interfaceType in objectType.GetInterfaces())
            {
                //加载dummyType
                OpCodesFactory.LdLocalVariable(generator, 0);

                //创建interface dummy type 
                //string nameSpace, string fullname, string name, Type value

                OpCodesFactory.LdString(generator, interfaceType.Namespace);
                OpCodesFactory.LdString(generator, interfaceType.FullName);
                OpCodesFactory.LdString(generator, interfaceType.Name);
                OpCodesFactory.LdType(generator, interfaceType);
                OpCodesFactory.CallMethod<DummyTypeHandlerFactory, CreateDummyTypeObjectAttribute>(generator);
                OpCodesFactory.CallVirtMethod<DummyType, DummyType.AddInterfaceAttribute>(generator);
                OpCodesFactory.Donothing(generator);
            }
        }
    }

    partial class DummyTypeHandlerFactory
    {

        [CreateDummyTypeList]
        internal static DummyType CreateDummyTypeList(DotNetPropertyType propertyType,
            string nameSpace, string fullname, string name, Type elementType)
        {
            DummyType dummy = new DummyType(nameSpace, fullname, name);
            dummy.PropertyType = propertyType;//XXXArray
            dummy.DeclaringType = null;
            dummy.IsGenericType = true;
            dummy.AddGenericArgument(CreateDummyTypeObject(elementType.Namespace, elementType.FullName, elementType.Name, elementType));
            return dummy;
        }

        /// <summary>
        /// 由于范型无法区分metadatatoken，所以必须连element也添加进来
        /// </summary>
        /// <param name="propertyType"></param>
        /// <param name="nameSpace"></param>
        /// <param name="fullname"></param>
        /// <param name="name"></param>
        /// <param name="metadataToken"></param>
        /// <param name="elementType"></param>
        /// <returns></returns>
        [CreateDummyTypeCollection]
        internal static DummyType CreateDummyTypeCollection(DotNetPropertyType propertyType,
            string nameSpace, string fullname, string name, Type elementType)
        {
            DummyType dummy = new DummyType(nameSpace, fullname, name);
            dummy.DataType = DotNetDataType.UNKNOWN;
            dummy.PropertyType = propertyType;//XXXArray
            dummy.DeclaringType = null;
            dummy.IsArray = true;
            dummy.SetElementType(CreateDummyTypeObject(elementType.Namespace, elementType.FullName, elementType.Name, elementType));
            return dummy;
        }

        /// <summary>
        /// 无剩余
        /// </summary>
        /// <param name="hander"></param>
        /// <param name="nameSpace"></param>
        /// <param name="fullname"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        [CreateDummyTypeObject]
        internal static IDummyType CreateDummyTypeObject(string nameSpace, string fullname, string name, Type value)
        {
            IDummyType valueType = DummyCacheFactory<IDummyType>.Instance.GetValue(nameSpace, fullname, name);

            if (valueType != null)
                return valueType;


            //如果缓存不存在 只能使用反射获取内部对象进行创建 性能下降

            LoggerHelper.Log("BufferCreate.DummyStructureSerializeObject({0},{1},{2})", nameSpace, fullname, name);

            DummyTypeHandler handler = CreateDummyTypeHandler(value);

            valueType = handler();
            
            DummyCacheFactory<IDummyType>.Instance.AddValue(nameSpace, fullname, name, valueType);

            return valueType;
        }

        [BufferDummyTypeObject]
        internal static void BufferDummyTypeObject(IDummyType type)
        {
            if (DummyCacheFactory<IDummyType>.Instance.Contains(type.Namespace, type.FullName, type.Name))
                return;

            LoggerHelper.Log("BufferCreate.BufferDummyStructureObject({0})", type);

            DummyCacheFactory<IDummyType>.Instance.AddValue(type.Namespace, type.FullName, type.Name, type);
        }



        /// <summary>
        /// 剩余property/attribute/assembly
        /// </summary>
        /// <param name="propertyType"></param>
        /// <param name="nameSpace"></param>
        /// <param name="fullname"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        [PrivateCreateDummyTypeObject]
        internal static DummyType PrivateCreateDummyTypeObject(DotNetPropertyType propertyType, string nameSpace, string fullname, string name)
        {
            LoggerHelper.Log("-> DummyTypeSerializeHandlerFactory.DummySerializeObject({0},{1},{2},{3})", propertyType, nameSpace, fullname, name);

            DummyType type = new DummyType(nameSpace, fullname, name);
            type.DataType = DotNetDataType.UNKNOWN;
            type.DeclaringType = null;
            type.PropertyType = propertyType;//interface / object
            return type;
        }

        /// <summary>
        /// 完成 无剩余
        /// </summary>
        /// <param name="nameSpace"></param>
        /// <param name="fullname"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        [CreateDummyTypeEnum]
        internal static DummyType CreateDummyTypeEnum(string assemblyName, string assemblyFileName,
            string nameSpace, string fullname, string name)
        {
            LoggerHelper.Log("-> DummyTypeSerializeHandlerFactory.DummySerializeEnum({0},{1},{2},{3},{4})",
                assemblyName, assemblyFileName, nameSpace, fullname, name);

            DummyType dummy = new DummyType(nameSpace, fullname, name);
            //dummy.MetadataToken = metadataToken;
            dummy.DataType = DotNetDataType.UNKNOWN;
            dummy.PropertyType = DotNetPropertyType.Enum;
            dummy.DeclaringType = null;
            dummy.CreateAssembly(assemblyName, assemblyFileName);
            return dummy;
        }

        /// <summary>
        /// 完成 无剩余
        /// </summary>
        /// <param name="fullname"></param>
        /// <param name="name"></param>
        /// <param name="datatype"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        [CreateDummyTypeValue]
        internal static DummyType CreateDummyTypeValue(string fullname, string name, DotNetDataType datatype)
        {
            LoggerHelper.Log("-> DummyTypeSerializeHandlerFactory.DummySerializeValue({0},{1},{2})", fullname, name, datatype);

            DummyType dummy = new DummyType("System", fullname, name);
            dummy.DataType = datatype;
            dummy.PropertyType = DotNetPropertyType.Value;
            dummy.DeclaringType = null;
            return dummy;
        }

        /// <summary>
        /// 无剩余
        /// </summary>
        /// <param name="hander"></param>
        /// <param name="nameSpace"></param>
        /// <param name="fullname"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        [CreateDummyTypeBinary]
        internal static DummyType CreateDummyTypeBinary(string fullname, string name)
        {
            LoggerHelper.Log("serialize binary:{0}", name);

            DummyType dummy = new DummyType("System", fullname, name);
            dummy.DataType = DotNetDataType.UNKNOWN;
            dummy.PropertyType = DotNetPropertyType.Binary;
            dummy.DeclaringType = null;

            DummyType elementType = new DummyType("System", "System.Byte", "Byte");
            elementType.DataType = DotNetDataType.Int32;
            elementType.PropertyType = DotNetPropertyType.Value;
            elementType.DeclaringType = null;
            dummy.SetElementType(elementType);
            return dummy;
        }

    }

    partial class DummyTypeHandlerFactory
    {
        class CreateDummyTypeListAttribute : Attribute { }
        class CreateDummyTypeCollectionAttribute : Attribute { }
        class CreateDummyTypeObjectAttribute : Attribute
        {
        }
        class CreateDummyTypeEnumAttribute : Attribute
        {
        }
        class CreateDummyTypeValueAttribute : Attribute
        {
        }
        class CreateDummyTypeBinaryAttribute : Attribute
        {
        }

        class BufferDummyTypeObjectAttribute : Attribute { }
        class PrivateCreateDummyTypeObjectAttribute : Attribute { }
    }
}
